import { ref } from 'vue';
import initSwc, * as swc from '@swc/wasm-web';
import type { ParseOptions, Module, Node, Config as SwcConfig } from '@swc/wasm-web';

const isInitialized = ref(false);
let initializePromise: Promise<void> | null = null;

/**
 * Initializes the SWC WASM module.
 * Ensures initialization only happens once.
 * 
 * @returns A promise that resolves when initialization is complete.
 */
async function initialize(): Promise<void> {
    if (isInitialized.value) {
        return Promise.resolve();
    }
    if (initializePromise) {
        return initializePromise;
    }

    initializePromise = (async () => {
        try {
            console.log('[SwcService] Initializing SWC WASM...');
            await initSwc();
            isInitialized.value = true;
            console.log('[SwcService] SWC WASM initialized successfully.');
        } catch (error) {
            console.error('[SwcService] Failed to initialize SWC WASM:', error);
            // Reject the promise so callers know initialization failed
            throw error; 
        } finally {
            initializePromise = null; // Reset promise allow retry? Maybe not.
        }
    })();

    return initializePromise;
}

/**
 * Parses the given code content using SWC.
 * Waits for SWC initialization if it hasn't completed yet.
 * 
 * @param content The code content (string).
 * @param options SWC parse options.
 * @returns A promise resolving to the parsed Module (AST).
 * @throws If SWC initialization fails or the parse function is unavailable.
 */
async function parseCode(content: string, options: ParseOptions): Promise<Module> {
    if (!isInitialized.value) {
        console.warn('[SwcService] SWC not initialized yet, awaiting initialization...');
        await initialize(); // Wait for the initialization promise
    }

    if (!isInitialized.value || typeof swc.parse !== 'function') {
         console.error('[SwcService] SWC initialization failed or swc.parse function unavailable.');
         throw new Error('SWC is not ready.');
    }

    // Now it's safe to call parse
    console.log(`[SwcService] Calling SWC parse via namespace with syntax: ${options.syntax}`);
    return swc.parse(content, options);
}

/**
 * Prints the given SWC AST Node back into a code string.
 * Waits for SWC initialization if it hasn't completed yet.
 * NOTE: Type signature might need adjustment based on SWC version.
 *
 * @param node The SWC AST Node to print (might need to be Program/Module).
 * @param options Optional SWC print options (using 'any' due to potential type issues).
 * @returns A promise resolving to the generated code string.
 * @throws If SWC initialization fails or the print function is unavailable.
 */
async function printAstNode(node: Node, options?: any): Promise<string> {
    if (!isInitialized.value) {
        console.warn('[SwcService] SWC not initialized yet, awaiting initialization...');
        await initialize(); 
    }

    if (!isInitialized.value || typeof swc.print !== 'function') {
         console.error('[SwcService] SWC initialization failed or swc.print function unavailable.');
         throw new Error('SWC is not ready to print.');
    }

    try {
        console.log(`[SwcService] Calling SWC print for node type: ${node.type}`);
        // Use type assertion 'as any' to bypass the specific Program/Module requirement for now
        const result = await swc.print(node as any, options); 
        return result.code;
    } catch (error) {
        console.error(`[SwcService] Error calling swc.print for node type ${node.type}:`, error);
        throw new Error(`SWC print failed: ${error instanceof Error ? error.message : String(error)}`);
    }
}

/**
 * Transpiles TypeScript code to JavaScript using SWC.
 * 
 * @param tsCode The TypeScript code string.
 * @param options Optional SWC transform options (SwcConfig).
 * @returns A promise resolving to the transpiled JavaScript code string.
 * @throws If SWC initialization or transformation fails.
 */
async function transpileTsToJs(tsCode: string, options?: SwcConfig): Promise<string> {
    if (!isInitialized.value) {
        console.warn('[SwcService] SWC not initialized yet, awaiting initialization...');
        await initialize(); // Wait for the initialization promise
    }

    if (!isInitialized.value || typeof swc.transform !== 'function') {
         console.error('[SwcService] SWC initialization failed or swc.transform function unavailable.');
         throw new Error('SWC is not ready to transform.');
    }

    // Default SWC options for TS -> JS transpilation
    const defaultOptions: SwcConfig = {
        jsc: {
            parser: {
                syntax: 'typescript', // Specify input syntax
                tsx: false, // Disable TSX unless needed
                decorators: false, // Disable decorators unless needed
                // Add other parser options if required
            },
            target: 'es2020', // Target modern JS environment
            loose: false, // Enable more spec-compliant transforms
            // Add other jsc options if required
        },
        module: {
            type: 'es6', // Keep ES module syntax
        },
        // Add source map options if needed
        // sourceMaps: true,
        // inlineSourcesContent: true,
    };

    const mergedOptions = { ...defaultOptions, ...options }; // Merge defaults with provided options

    try {
        console.log('[SwcService] Calling SWC transform...');
        const result = await swc.transform(tsCode, mergedOptions);
        console.log('[SwcService] SWC transform successful. Output length:', result.code.length);
        return result.code;
    } catch (error) {
        console.error('[SwcService] Error calling swc.transform:', error);
        throw new Error(`SWC transform failed: ${error instanceof Error ? error.message : String(error)}`);
    }
}

// Export the service functions including the new one
export const swcService = {
    initialize,
    parseCode,
    printAstNode,
    transpileTsToJs, // Export the new function
    isInitialized: isInitialized, 
}; 